#pragma once


#include<iostream>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<cstring>
#include<netinet/in.h>//定义数据结构sockaddr_in
#include<arpa/inet.h> //提供IP地址转换函数
#include<pthread.h>
#include<unistd.h>
#include"Log.hpp"
#define BACKLOG 5

class TcpServer//采用单例懒汉模式
{
    private:
    int port;
    int listen_sock;
    static TcpServer *svr;


  private:
  TcpServer(int _port):port(_port),listen_sock(-1)
  {}
  TcpServer(const TcpServer &s){}
 public:
  static TcpServer *getinstance(int port)
  {
      //定义一把锁
      static pthread_mutex_t lock =PTHREAD_MUTEX_INITIALIZER;//用宏对锁初始化
      if(nullptr==svr)
      {
          pthread_mutex_lock(&lock);
          if(nullptr==svr)
          {
              svr=new TcpServer(port);
              svr->InitServer();
          }
          pthread_mutex_unlock(&lock);
      }
      return svr;
  }
  
  
    //初始化
  void InitServer()
  {
      Socket();
      Bind();
      Listen();
      LOG(INFO,"tcp_server init... success!");


  }
  //创建套接字
  void Socket()
  {
      listen_sock=socket(AF_INET,SOCK_STREAM,0);
      //创建失败
      if(listen_sock<0)
      {
        LOG(FATAL,"socket error!");
          exit(1);
      }
      //地址复载，保证服务器宕机时，重启成功
      int opt=1;
      setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
     LOG(INFO,"create socket... success!");
  }
  //绑定，将用户设置的ip和port在内核中和我们的进程强关联
        //   void Bind()
        // {
        //     struct sockaddr_in local;
        //     memset(&local, 0, sizeof(local));
        //     local.sin_family = AF_INET;
        //     local.sin_port = htons(port);
        //     local.sin_addr.s_addr = INADDR_ANY; //云服务器不能直接绑定公网IP

        //     if(bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){
        //         LOG(FATAL, "bind error!");
        //         exit(2);
        //     }
        //     LOG(INFO, "bind socket ... success");
        // }

  void Bind()
  {
      struct sockaddr_in local;
      memset(&local,0,sizeof(local));
      //要用来定义是哪种地址族
      local.sin_family=AF_INET;
      //调用htos()把主机端口号转为网络类型
      local.sin_port=htons(port);
      //云服务器不能直接绑定公网IP，让服务器自动绑定
      local.sin_addr.s_addr=INADDR_ANY;

      //绑定失败
      if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0)
      {
        LOG(FATAL,"bind error!");
          exit(2);
      }
       LOG(INFO,"bind socket... success!");
  }
  //监听
  void Listen()
  {
    //第一个参数: int sock: 希望进入等待连接请求状态的套接字文件描述符
    // ,传递的描述符套接字参数成为服务器端套接字(监听套接字!!!!)
    //第二个参数: int backlog: 连接请求等待队列的长度,若为5,则队列长度为5,
     //表示最多使5个连接请求进入队列,其中也包含排队建立3次握手队列和刚刚建立3次握手队列的连接数之和
      if(listen(listen_sock,BACKLOG)<0)
      {
        LOG(FATAL,"listen error!");
          exit(3);
      }
     LOG(INFO,"listen socket... success!");

  }
  int Sock()
  {
      return listen_sock;
  }
  ~TcpServer()
  {
    if(listen_sock>=0)
    close(listen_sock);
  }
};
 
 TcpServer * TcpServer::svr= nullptr;//静态成员类外类外初始化
